import React from 'react'
import { TreeNode, createResource } from '@designable/core'
import {
  useTreeNode,
  TreeNodeWidget,
  DroppableWidget,
  useNodeIdProps,
  DnFC,
} from '@designable/react'
import { ArrayBase } from '@formily/antd'
import { observer } from '@formily/react'
import { LoadTemplate } from '../../common/LoadTemplate'
import { useDropTemplate } from '../../hooks'
import {
  hasNodeByComponentPath,
  queryNodesByComponentPath,
  createEnsureTypeItemsNode,
  findNodeByComponentPath,
  createNodeId,
} from '../../shared'
import { createArrayBehavior } from '../ArrayBase'
import cls from 'classnames'
import './styles.less'

const ensureObjectItemsNode = createEnsureTypeItemsNode('object')

const isArrayItemsOperation = (name: string) =>
  name === 'ArrayItems.Remove' ||
  name === 'ArrayItems.SortHandle'

export const ArrayItems: DnFC<React.HTMLAttributes<HTMLDivElement>> = observer((props) => {
  const node = useTreeNode()
  const nodeId = useNodeIdProps()
  const designer = useDropTemplate('ArrayItems', (source) => {
    const sortHandleNode = new TreeNode({
      componentName: node.componentName,
      props: {
        type: 'void',
        'x-component': 'ArrayItems.SortHandle',
      },
    })
    const removeNode = new TreeNode({
      componentName: node.componentName,
      props: {
        type: 'void',
        title: 'Remove',
        'x-component': 'ArrayItems.Remove',
      },
    })

    const objectNode = new TreeNode({
      componentName: node.componentName,
      props: {
        type: 'object',
      },
      children: [sortHandleNode, ...source, removeNode],
    })
    const additionNode = new TreeNode({
      componentName: node.componentName,
      props: {
        type: 'void',
        title: '新增',
        'x-component': 'ArrayItems.Addition',
      },
    })
    return [objectNode, additionNode]
  })
  const renderItems = () => {
    if (node.children.length === 0) return <DroppableWidget />
    const additions = queryNodesByComponentPath(node, [
      'ArrayItems',
      'ArrayItems.Addition',
    ])
    const sortHandles = queryNodesByComponentPath(node, [
      'ArrayItems',
      '*',
      'ArrayItems.SortHandle',
    ])
    const operations = queryNodesByComponentPath(node, [
      'ArrayItems',
      '*',
      isArrayItemsOperation,
    ])
    const children = queryNodesByComponentPath(node, [
      'ArrayItems',
      '*',
      (name) => name.indexOf('ArrayItems.') === -1,
    ])
    return (
      <ArrayBase disabled>
        <ArrayBase.Item index={0} record={null}>
          <div
            {...props}
            className={cls('ant-formily-array-items-item', props.className)}
          >
            <div {...createNodeId(designer, ensureObjectItemsNode(node).id)}>
              {sortHandles.map((node) => (
                <TreeNodeWidget key={node.id} node={node} />
              ))}
              {children.length ? (
                children.map((node) => (
                  <TreeNodeWidget key={node.id} node={node} />
                ))
              ) : (
                <DroppableWidget hasChildren={false} />
              )}
              {operations
                .filter((node) => node.props['x-component'] === 'ArrayItems.Remove')
                .map((node) => (
                  <TreeNodeWidget key={node.id} node={node} />
                ))}
            </div>
          </div>
        </ArrayBase.Item>
        {additions.map((node) => (
          <TreeNodeWidget key={node.id} node={node} />
        ))}
      </ArrayBase>
    )
  }

  return (
    <div {...nodeId} className="dn-array-items">
      {renderItems()}
      <LoadTemplate
        actions={[
          {
            title: node.getMessage('addSortHandle'),
            icon: 'AddSort',
            onClick: () => {
              if (
                hasNodeByComponentPath(node, [
                  'ArrayItems',
                  '*',
                  'ArrayItems.SortHandle',
                ])
              )
                return
              const sortHandleNode = new TreeNode({
                componentName: node.componentName,
                props: {
                  type: 'void',
                  'x-component': 'ArrayItems.SortHandle',
                },
              })
              ensureObjectItemsNode(node).prepend(sortHandleNode)
            },
          },
          {
            title: node.getMessage('addOperation'),
            icon: 'AddOperation',
            onClick: () => {
              const oldAdditionNode = findNodeByComponentPath(node, [
                'ArrayItems',
                'ArrayItems.Addition',
              ])
              if (!oldAdditionNode) {
                const additionNode = new TreeNode({
                  componentName: node.componentName,
                  props: {
                    type: 'void',
                    title: 'Addition',
                    'x-component': 'ArrayItems.Addition',
                  },
                })
                ensureObjectItemsNode(node).insertAfter(additionNode)
              }
              const oldRemoveNode = findNodeByComponentPath(node, [
                'ArrayItems',
                '*',
                'ArrayItems.Remove',
              ])
              if (!oldRemoveNode) {
                ensureObjectItemsNode(node).append(
                  new TreeNode({
                    componentName: node.componentName,
                    props: {
                      type: 'void',
                      'x-component': 'ArrayItems.Remove',
                    },
                  })
                )
              }
            },
          },
        ]}
      />
    </div>
  )
})

ArrayBase.mixin(ArrayItems)

ArrayItems.Behavior = createArrayBehavior('ArrayItems')

ArrayItems.Resource = createResource({
  icon: 'ArrayItemsSource',
  elements: [
    {
      componentName: 'Field',
      props: {
        type: 'array',
        'x-decorator': 'FormItem',
        'x-component': 'ArrayItems',
        'x-component-props': {},
      },
    },
  ],
})

